﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace TravelAgency.DAL
{
    public class TravelAgencyDAO : IDisposable
    {
        private TravelAgencyEntities context;

        public TravelAgencyDAO()
        {
            this.context = new TravelAgencyEntities();
        }

        #region Trips

        public Trip AddTrip(string title,
            string description,
            DateTime startDate,
            DateTime endDate,
            decimal price,
            int maxPeopleCapacity,
            int? photoId = null)
        {
            Trip trip = new Trip();

            trip.Title = title;
            trip.Description = description;
            trip.StartDate = startDate;
            trip.EndDate = endDate;
            trip.Price = price;
            trip.MaxPeopleCapacity = maxPeopleCapacity;
            trip.CurrentPeopleCapacity = 0;
            trip.PhotoId = photoId;

            this.Add(trip);
            return trip;
        }

        public void Add(Trip trip)
        {
            this.context.Add(trip);
        }

        public IQueryable<int> GetTripIds()
        {
            return this.context.Trips.Select(t => t.TripId);
        }

        public IQueryable<Trip> GetTrips()
        {
            return this.context.Trips;
        }

        public Trip GetTripByTripId(int tripId)
        {
            return this.context.Trips.First(t => t.TripId == tripId);
        }

        public bool TryGetTripByTripId(int tripId, out Trip trip)
        {
            trip = this.context.Trips.FirstOrDefault(t => t.TripId == tripId);
            return trip != null;
        }

        public IQueryable<Trip> GetTripsByTitle(string title)
        {
            var trips = this.context.Trips.Where(t => t.Title == title);
            return trips;
        }

        public IQueryable<Trip> GetTripsBySubstringInTitle(string substring)
        {
            var trips = this.context.Trips.Where(t => t.Title.Contains(substring));
            return trips;
        }
      
        public IQueryable<Trip> GetTripsBySubstringsInTitle(IEnumerable<string> substrings)
        {
            IQueryable<Trip> trips = this.context.Trips;

            foreach (string substring in substrings)
            {
                string substringLocalValue = substring;
                trips = trips.Where(t => t.Title.Contains(substringLocalValue));
            }

            return trips;
        }

        public IQueryable<Trip> GetTripsBySubstringInDescription(string substring)
        {
            var trips = this.context.Trips.Where(t => t.Description.Contains(substring));
            return trips;
        }

        public IQueryable<Trip> GetTripsBySubstringsInDescription(IEnumerable<string> substrings)
        {
            IQueryable<Trip> trips = this.context.Trips;

            foreach (string substring in substrings)
            {
                string substringLocalValue = substring;
                trips = trips.Where(t => t.Description.Contains(substringLocalValue));
            }

            return trips;
        }

        public IQueryable<Trip> GetTripsWithPhoto()
        {
            var trips = context.Trips.Where(t => t.PhotoId != null);
            return trips;
        }

        public IQueryable<Trip> GetTripsBetween(DateTime startDate, DateTime endDate)
        {
            var trips = context.Trips.Where(t => t.StartDate >= startDate && t.EndDate <= endDate);
            return trips;
        }

        public void Delete(Trip trip)
        {
            this.context.Delete(trip);
        }

        public void DeleteTripByTripId(int tripId)
        {
            Trip trip = this.context.Trips.FirstOrDefault(t => t.TripId == tripId);

            if (trip == null)
            {
                return; // don't throw exception, the trip is not present so job is done
            }

            this.Delete(trip);
        }
        
        //methods added

        public void UpdateTrip(int tripId, string title, string description,
            DateTime startDate, DateTime endDate, decimal price, int capacity)
        {
            Trip tripToUpdate = this.context.Trips.First(t => t.TripId == tripId);

            tripToUpdate.Title = title;
            tripToUpdate.Description = description;
            tripToUpdate.StartDate = startDate;
            tripToUpdate.EndDate = endDate;
            tripToUpdate.Price = price;
            tripToUpdate.MaxPeopleCapacity = capacity;
        }

        public void DeleteTripWithTripReservationsByTripId(int tripId)
        {
            IEnumerable<Reservation> reservations =
                    this.context.Reservations.Where(r => r.TripId == tripId);
            List<Reservation> reservationsToDelete = reservations.ToList();

            foreach (Reservation reservation in reservationsToDelete)
            {
                this.context.Delete(reservation);
            }

            this.DeleteTripByTripId(tripId);
        }         

        #endregion Trips

        #region Photos

        public Photo AddPhoto(string name, byte[] content)
        {
            Photo photo = new Photo();
            photo.Name = name;
            photo.PhotoContent = content;

            this.Add(photo);
            return photo;
        }

        public void Add(Photo photo)
        {
            this.context.Add(photo);
        }      

        public IQueryable<int> GetPhotoIds()
        {
            return this.context.Photos.Select(ph => ph.PhotoId);
        }

        public IQueryable<Photo> GetPhotos()
        {
            return this.context.Photos;
        }

        public Photo GetPhotoByPhotoId(int photoId)
        {
            Photo photo = this.context.Photos.First(ph => ph.PhotoId == photoId);
            return photo;
        }

        public string GetPhotoNameByPhotoId(int photoId)
        {
            Photo photo = this.context.Photos.First(ph => ph.PhotoId == photoId);
            return photo.Name;
        }

        public IQueryable<Photo> GetPhotosBySubstringInName(string substring)
        {
            var photos = this.context.Photos.Where(ph => ph.Name.Contains(substring));
            return photos;
        }

        public IQueryable<Photo> GetPhotosBySubstringsInName(IEnumerable<string> substrings)
        {
            IQueryable<Photo> photos = this.context.Photos;

            foreach (string substring in substrings)
            {
                string substringLocalValue = substring;
                photos = photos.Where(ph => ph.Name.Contains(substringLocalValue));
            }

            return photos;
        }

        public IQueryable<Photo> GetPhotosByName(string name)
        {
            var photos = this.context.Photos.Where(ph => ph.Name == name);
            return photos;
        }

        public void Delete(Photo photo)
        {
            this.context.Delete(photo);
        }

        public void DeletePhotoByPhotoId(int photoId)
        {
            Photo photo = this.context.Photos.FirstOrDefault(ph => ph.PhotoId == photoId);

            if (photo == null)
            {
                return; // don't throw exception, the photo is not present so job is done
            }

            this.Delete(photo);
        }

        #endregion Photos

        #region Reservations

        public IQueryable<int> GetReservationIds()
        {
            return this.context.Reservations.Select(r => r.ReservationId);
        }

        public IQueryable<Reservation> GetReservations()
        {
            return this.context.Reservations;
        }

        public Reservation GetReservationByReservationId(int reservationId)
        {
            return this.context.Reservations.First(r => r.ReservationId == reservationId);
        }

        public IQueryable<Reservation> GetReservationsByTripId(int tripId)
        {
            return this.context.Reservations.Where(r => r.TripId == tripId);
        }

        public IQueryable<Reservation> GetReservationsByUserId(Guid userId)
        {
            return this.context.Reservations.Where(r => r.UserId == userId);
        }

        public void Delete(Reservation reservation)
        {
            this.context.Delete(reservation);
        }

        public void DeleteReservationByReservationId(int reservationId)
        {
            Reservation reservation = this.context.Reservations.First(r => r.ReservationId == reservationId);

            if (reservation == null)
            {
                return; // don't throw exception, reservation is not present so job is done
            }

            this.Delete(reservation);
        }

        public void DeleteReservationsByUserId(Guid userId)
        {
            List<Reservation> reservations =
                this.context.Reservations.Where(r => r.UserId == userId).ToList();
            if (reservations == null)
            {
                return; // don't throw exception, reservation is not present so job is done
            }

            foreach (Reservation reservation in reservations)
            {
                reservation.Trip.CurrentPeopleCapacity -= reservation.PeopleCount;
                this.DeleteReservationByReservationId(reservation.ReservationId);
            }
        }

        public void CancelReservationByReservationId(int reservationId)
        {
            Reservation reservationToCancel = this.context.Reservations.First(r => r.ReservationId == reservationId);
            reservationToCancel.Trip.CurrentPeopleCapacity -= reservationToCancel.PeopleCount;
            this.DeleteReservationByReservationId(reservationId);
        }

        #endregion Reservations

        public void SaveChanges()
        {
            this.context.SaveChanges();
        }

        public void Dispose()
        {
            this.context.Dispose();
        }
    }
}
